package lifo.util;

import java.util.Arrays;
import java.util.Iterator;

public class BooleanSet implements Iterable<Integer> {
	private boolean[] val;
	private int size;
	public static final BooleanSet EMPTY = new BooleanSet(new boolean[] {}, 0);

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + Arrays.hashCode(val);
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		BooleanSet other = (BooleanSet) obj;
		if (size != other.size)
			return false;
		if (!Arrays.equals(val, other.val))
			return false;
		return true;
	}

	private class BooleanSetIterator implements Iterator<Integer> {
		int cpt = 0;

		public BooleanSetIterator() {
			while (cpt < val.length && !val[cpt])
				cpt++;
		}

		public boolean hasNext() {
			return cpt == val.length;
		}

		public Integer next() {
			int res = cpt;
			while (cpt < val.length && !val[cpt])
				cpt++;
			return res;
		}

		public void remove() {
		}
	}

	public Iterator<Integer> iterator() {
		return new BooleanSetIterator();
	}

	private BooleanSet(boolean[] val, int size) {
		super();
		this.val = val;
		this.size = size;
	}

	public static BooleanSet empty() {
		return EMPTY;
	}

	public static BooleanSet all(int n) {
		boolean[] res = new boolean[n];
		Arrays.fill(res, true);
		return new BooleanSet(res, n);
	}

	public static BooleanSet singleton(int n) {
		boolean[] res = new boolean[n + 1];
		Arrays.fill(res, false);
		res[n] = true;
		return new BooleanSet(res, 1);
	}

	public boolean contains(int n) {
		return n < val.length && val[n];
	}

	public boolean isEmpty() {
		return size == 0;
	}

	public void add(int n) {
		if (n < val.length) {
			if (!val[n])
				size++;
			val[n] = true;
		} else {
			size++;
			val = Arrays.copyOf(val, n + 1);
			val[n] = true;
		}
	}

	public void remove(int n) {
		if (n < val.length && val[n]) {
			size--;
			val[n] = false;
		}
	}

	public int[] toArray() {
		int[] res = new int[size];
		int ctp = 0;
		for (int i : this) {
			res[ctp] = i;
			ctp++;
		}
		return res;
	}

	public String toString() {
		if (size == 0)
			return "{}";
		else {
			StringBuffer res = new StringBuffer("{");
			for (int i : this) {
				res.append(i + ",");
			}
			res.setCharAt(res.length() - 1, '}');
			return res.toString();
		}
	}
}
